// edtFTPnet
// 
// Copyright (C) 2004 Enterprise Distributed Technologies Ltd
// 
// www.enterprisedt.com
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Bug fixes, suggestions and comments should posted on 
// http://www.enterprisedt.com/forums/index.php
// 
// Change Log:
// 
// $Log: FTPFile.cs,v $
// Revision 1.18  2011-03-04 06:36:08  bruceb
// FTPFileCallback
//
// Revision 1.17  2010-09-27 05:11:57  hans
// Added Identifier property.
//
// Revision 1.16  2007-06-26 01:36:32  bruceb
// CF changes
//
// Revision 1.15  2007-06-20 08:44:34  hans
// Added setters for several attributes.
//
// Revision 1.14  2007-05-23 06:41:29  hans
// Added internal methods SetName and SetLastModified.
//
// Revision 1.13  2007-05-23 00:27:46  hans
// Added ApplyTimeDifference method.
//
// Revision 1.12  2007-05-15 01:05:08  bruceb
// changes re standard
//
// Revision 1.11  2007/04/26 04:29:57  hans
// Added constructor that takes path.
//
// Revision 1.10  2007/04/21 22:08:14  bruceb
// path & children added.
//
// Revision 1.9  2007/02/02 01:42:18  bruceb
// added OS400 type
//
// Revision 1.8  2005/08/04 21:57:58  bruceb
// fixed comment
//
// Revision 1.7  2005/07/22 10:35:18  hans
// made CLS compliant for the purpose of strong naming
//
// Revision 1.6  2005/06/03 11:32:47  bruceb
// vms changes
//
// Revision 1.5  2005/02/07 17:19:13  bruceb
// constructor made public
//
// Revision 1.4  2004/11/05 20:00:28  bruceb
// cleaned up namespaces
//
// Revision 1.3  2004/10/29 09:41:44  bruceb
// removed /// in file header
//
//
//

using System;
using System.Globalization;
using System.Text;

namespace EnterpriseDT.Net.Ftp
{
    /// <summary>  
    /// Represents a remote file (implementation)
    /// </summary>
    /// <author>
    /// Bruce Blackshaw       
    /// </author>
    /// <version>      
    /// $Revision: 1.18 $
    /// </version>
    public class FTPFile
    {
        /// <summary> Unknown remote server type</summary>
        public const int UNKNOWN = - 1;

        /// <summary> Windows type</summary>
        public const int WINDOWS = 0;

        /// <summary> UNIX type</summary>
        public const int UNIX = 1;

        /// <summary> VMS type</summary>
        public const int VMS = 2;

        public const int OS400 = 3;

        /// <summary>Date format</summary>
        private static readonly string format = "dd-MM-yyyy HH:mm";

        /// <summary> Type of file</summary>
        private readonly int type;

        /// <summary> File/dir name</summary>
        protected internal string fileName;

        /// <summary> Owner if known</summary>
        protected internal string fileOwner;

        /// <summary>Directory if known</summary>
        protected string filePath;

        /// <summary> Permission bits string</summary>
        protected internal string filePermissions;

        /// <summary> Size of file</summary>
        protected internal long fileSize;

        /// <summary> Is this a directory?</summary>
        protected internal bool isDir;

        /// <summary> Is this file a symbolic link?</summary>
        protected internal bool isLink;

        /// <summary>Children if a directory</summary>
        protected FTPFile[] kids;

        /// <summary> Last modified</summary>
        protected internal DateTime lastModifiedTime;

        /// <summary> Number of links to file</summary>
        protected internal int linkNum = 1;

        /// <summary> Name of file this is linked to</summary>
        protected internal string linkedFileName;

        /// <summary> Raw string</summary>
        protected internal string rawRep;

        /// <summary> Group if known</summary>
        protected internal string userGroup;

        /// <summary> 
        /// Constructor
        /// </summary>
        /// <param name="type">         
        /// type of file
        /// </param>
        /// <param name="raw">          
        /// raw string returned from server
        /// </param>
        /// <param name="name">         
        /// name of file
        /// </param>
        /// <param name="size">         
        /// size of file
        /// </param>
        /// <param name="isDir">        
        /// true if a directory
        /// </param>
        /// <param name="lastModifiedTime"> 
        /// last modified timestamp
        /// </param>
        public FTPFile(int type, string raw, string name, long size,
                       bool isDir, ref DateTime lastModifiedTime)
        {
            this.type = type;
            rawRep = raw;
            fileName = name;
            fileSize = size;
            this.isDir = isDir;
            this.lastModifiedTime = lastModifiedTime;
        }

        /// <summary> 
        /// Constructor
        /// </summary>
        /// <param name="name">         
        /// name of file
        /// </param>
        /// <param name="size">         
        /// size of file
        /// </param>
        /// <param name="isDir">        
        /// true if a directory
        /// </param>
        /// <param name="lastModifiedTime"> 
        /// last modified timestamp
        /// </param>
        internal FTPFile(string name, long size, bool isDir, DateTime lastModifiedTime)
        {
            type = UNKNOWN;
            rawRep = "";
            fileName = name;
            fileSize = size;
            this.isDir = isDir;
            this.lastModifiedTime = lastModifiedTime;
        }

        /// <summary> 
        /// Constructor
        /// </summary>
        /// <param name="name">         
        /// name of file
        /// </param>
        /// <param name="size">         
        /// size of file
        /// </param>
        /// <param name="isDir">        
        /// true if a directory
        /// </param>
        /// <param name="lastModifiedTime"> 
        /// last modified timestamp
        /// </param>
        /// <param name="path"> 
        /// full path of file
        /// </param>
        internal FTPFile(string name, long size, bool isDir, DateTime lastModifiedTime, string path)
        {
            type = UNKNOWN;
            rawRep = "";
            fileName = name;
            fileSize = size;
            this.isDir = isDir;
            this.lastModifiedTime = lastModifiedTime;
            filePath = path;
        }

        /// <summary> 
        /// Get the type of file, eg UNIX
        /// </summary>
        /// <returns> the integer type of the file
        /// </returns>
        public int Type
        {
            get { return type; }
        }

        /// <returns> 
        /// Returns the name.
        /// </returns>
        public string Name
        {
            get { return fileName; }
            set { fileName = value; }
        }

        /// <returns> 
        /// Returns the raw server string.
        /// </returns>
        public string Raw
        {
            get { return rawRep; }
        }

        /// <returns> 
        /// Returns or sets the number of links to the file
        /// </returns>
        public int LinkCount
        {
            get { return linkNum; }

            set { linkNum = value; }
        }

        /// <returns> 
        /// Is this file a link
        /// </returns>
        public bool Link
        {
            get { return isLink; }

            set { isLink = value; }
        }


        /// <returns> 
        /// Returns the linked name.
        /// </returns>
        public string LinkedName
        {
            get { return linkedFileName; }
            set { linkedFileName = value; }
        }


        /// <returns> 
        /// Gets or sets the group.
        /// </returns>
        public string Group
        {
            get { return userGroup; }
            set { userGroup = value; }
        }

        /// <returns> 
        /// Gets or sets the owner.
        /// </returns>
        public string Owner
        {
            get { return fileOwner; }
            set { fileOwner = value; }
        }


        /// <returns> 
        /// Gets or sets whether this is a directory
        /// </returns>
        public bool Dir
        {
            get { return isDir; }
            set { isDir = value; }
        }

        /// <returns> 
        /// Path of file if set
        /// </returns>
        public string Path
        {
            get { return filePath; }
            set { filePath = value; }
        }

        /// <returns> 
        /// Identifier
        /// </returns>
        /// <remarks>If the server (e.g. Google Docs) uses provides an identifier in addition to the file-name then
        /// this property will return this identifier.</remarks>
        public string Identifier { get; set; }

        /// <returns> 
        /// If a directory, returns its children
        /// </returns>
        public FTPFile[] Children
        {
            get { return kids; }
            set { kids = value; }
        }

        /// <returns> 
        /// Gets or sets the permissions.
        /// </returns>
        public string Permissions
        {
            get { return filePermissions; }
            set { filePermissions = value; }
        }

        /// <returns> 
        /// Gets last modified timestamp
        /// </returns>
        public DateTime LastModified
        {
            get { return lastModifiedTime; }
            set { lastModifiedTime = value; }
        }


        /// <returns> 
        /// Gets size of file
        /// </returns>
        public long Size
        {
            get { return fileSize; }
            set { fileSize = value; }
        }

        /// <summary>
        /// Sets the <see cref="LastModified"/> time.
        /// </summary>
        /// <param name="time"></param>
        /// <param name="timeDifference"></param>
        internal void SetLastModified(DateTime time, TimeSpan timeDifference)
        {
            lastModifiedTime = time;
            ApplyTimeDifference(timeDifference);
        }

        /// <summary>
        /// Subtracts the given <see cref="TimeSpan"/> to the <see cref="LastModified"/> timestamp.
        /// </summary>
        /// <param name="difference">Time-span to add.</param>
        internal void ApplyTimeDifference(TimeSpan difference)
        {
            lastModifiedTime = lastModifiedTime - difference;
        }

        /// <returns> 
        /// string representation
        /// </returns>
        public override string ToString()
        {
            var buf = new StringBuilder(rawRep);
            buf.Append("[").Append("Name=").Append(fileName).Append(",").Append("Size=").
                Append(fileSize).Append(",").Append("Permissions=").Append(filePermissions).
                Append(",").Append("Owner=").Append(fileOwner).Append(",").
                Append("Group=").Append(userGroup).Append(",").Append("Is link=").Append(isLink).
                Append(",").Append("Link count=").Append(linkNum).Append(",").
                Append("Is dir=").Append(isDir).Append(",").
                Append("Linked name=").Append(linkedFileName).Append(",").
                Append("Permissions=").Append(filePermissions).Append(",").
                Append("Last modified=").Append(lastModifiedTime.ToString(format,
                                                                          CultureInfo.CurrentCulture.DateTimeFormat)).
                Append("]");
            return buf.ToString();
        }
    }

    #region FTPFileCallback

    /// <summary>
    /// Delegate for passing a single FTPFile object.  Used in directory-listing callbacks.
    /// </summary>
    /// <param name="file">The file.</param>
    public delegate void FTPFileCallback(FTPFile file);

    #endregion
}